// `include    "top_define.v"

module renew ( 
            clk,
                      rst_n,
 ///  connect with cpu                     
                      wr_en_cpu,
                      multi_modify_cpu,
                      multi_group_mac_cpu,
                      multi_member_cpu,

                      cpu_rd_multicam_cpu_vld,
                      cpu_rd_multicam_rden      ,
                      cpu_rd_multicam_address_cpu,
                      cpu_rd_multicam_cpu,
 //   connect with multi_hash
                     
                      multi_hash_en,
                      multi_hash_mac,
                      multi_mac,
                      multi_mac_hash_en,
                      hash_busy,

//    connect with lookup
             

                      rd_mac,
                      lookup_busy,
                      renew_busy,
//    connect with multi_addr_table
                       
                      wren_a,
                      rd_addr_a,
                      data_a,
                      q_a    ,
                                         
                      ini_multitable_busy

                     );
                     
input clk;
input rst_n;
output  renew_busy;

//  connect with  cpu_interface
input wr_en_cpu;
input [31:0]multi_modify_cpu;
input [31:0]multi_group_mac_cpu;
input [31:0]multi_member_cpu;

input         cpu_rd_multicam_rden      ;
input [11:0]  cpu_rd_multicam_address_cpu;
output reg [31:0] cpu_rd_multicam_cpu;
output reg cpu_rd_multicam_cpu_vld;
//  connect with  multi_hash

input  multi_hash_en;
input  [9:0] multi_hash_mac;
output [23:0] multi_mac;
output multi_mac_hash_en;
input  hash_busy;

//  connect with  lookup

input  [23:0]rd_mac;
input  lookup_busy;

//    connect with multi_addr_table
                       
output  reg wren_a;
output  [9:0]rd_addr_a;
output  reg[71:0]data_a;
input   [71:0]q_a;
output reg ini_multitable_busy;



reg renew_busy;
//  connect with  multi_hash


reg [23:0] multi_mac;
reg multi_mac_hash_en;


//  connect with  lookup

reg [23:0]wr_mac;

//    connect with  multi_addr_table
                       
reg  [9:0]addr_a;
wire [9:0] rd_addr_a;


reg [23:0]multi_mac_cpu_reg;
reg [7:0]multi_group_cpu_reg;
reg [31:0]multi_member_cpu_reg;
reg [9:0]multi_hash_mac_reg;
reg [1:0]modify_reg;

reg cpu_rd_multicam_rden_d1;
reg renew_done;
reg read_now;

reg [3:0]step;

reg[5:0] state;
reg[5:0] next_state;

parameter  idle             = 6'b000000,
           hash_wait        = 6'b000001,
           hash             = 6'b000010,
           lookup_wait      = 6'b000100,
           renew            = 6'b001000,
           read_cam         = 6'b010000,  
           ini_table        = 6'b100000;

//检测读地址是否冲突
always @ (posedge clk or negedge rst_n)
  if(~rst_n)
    read_now <=  1'b0;
  // else if(lookup_busy==1'b1 && wr_mac==rd_mac && cpu_rd_multicam_rden)
  else if(lookup_busy==1'b1 && wr_mac==rd_mac)
    read_now <=  1'b1;
  else
    read_now <=  1'b0;

always @ (posedge clk or negedge rst_n)begin
  if(~rst_n)
    cpu_rd_multicam_rden_d1 <= 1'b0;
  else
    cpu_rd_multicam_rden_d1 <= cpu_rd_multicam_rden;
end
           
always @ (posedge clk or negedge rst_n)
  if(~rst_n)
    state <=  idle;
  else
    state <=  next_state;

  assign rd_addr_a=  (cpu_rd_multicam_rden)? cpu_rd_multicam_address_cpu[9:0] :addr_a; // 2022.5.17, xym
  // assign rd_addr_a=  (cpu_rd_multicam_rden)? cpu_rd_multicam_address_cpu[11:2] :addr_a;
  reg [11:0] cpu_rd_multicam_address_cpu_reg;
  always @ (posedge clk or negedge rst_n)
  if(~rst_n)
    cpu_rd_multicam_address_cpu_reg<=12'd0;
  else if(cpu_rd_multicam_rden)
    cpu_rd_multicam_address_cpu_reg<=cpu_rd_multicam_address_cpu;
  else
    cpu_rd_multicam_address_cpu_reg<=cpu_rd_multicam_address_cpu_reg;
  
  always @(posedge clk or negedge rst_n)
  begin
    if(~rst_n)
      cpu_rd_multicam_cpu <= 32'b0;
    else if(cpu_rd_multicam_rden_d1)
      case(cpu_rd_multicam_address_cpu_reg[11:10]) // 2022.5.17, xym
          2'b10: cpu_rd_multicam_cpu<=q_a[71:40];
          2'b11: cpu_rd_multicam_cpu<=q_a[39:8];
          2'b00: cpu_rd_multicam_cpu<={24'b0,q_a[7:0]};
      // case(cpu_rd_multicam_address_cpu_reg[1:0])
      //     2'h0: cpu_rd_multicam_cpu<={24'b0,q_a[71:65],q_a[32]};
      //     2'h1: cpu_rd_multicam_cpu<=q_a[31:0];
      //     2'h2: cpu_rd_multicam_cpu<={24'b0,q_a[40:33]};
      //     2'h3: cpu_rd_multicam_cpu<={8'b0,q_a[64:41]};
   	    default: cpu_rd_multicam_cpu<=32'b0;
      endcase    
    else        
      cpu_rd_multicam_cpu<=cpu_rd_multicam_cpu;
  end

always @(posedge clk or negedge rst_n)begin
  if(~rst_n)
    cpu_rd_multicam_cpu_vld <= 1'b0;
  else if(cpu_rd_multicam_rden_d1)
    cpu_rd_multicam_cpu_vld <= 1'b1;
  else 
    cpu_rd_multicam_cpu_vld <= 1'b0;
end
  
  reg  ini_table_done;
  reg  [9:0]ini_addr;
always @ (posedge clk or negedge rst_n)
  if(~rst_n)
    ini_table_done<=1'b0;
  else if(state==ini_table && ini_addr==10'h3ff)
    ini_table_done<=1'b1;

always @ (posedge clk or negedge rst_n)
  if(~rst_n)
    ini_multitable_busy<=1'b0;
  else 
    ini_multitable_busy<=~ini_table_done;
always@(posedge clk or negedge rst_n)
  if(~rst_n)
    ini_addr <= 10'd0;
  else if( next_state == ini_table)
    ini_addr <= ini_addr + 10'd1;
  else 
    ini_addr <= 10'd0;
always @ (*)
  case(state)
    idle:
      if(ini_table_done==1'b0)
        next_state = ini_table;
      else if(wr_en_cpu)
        next_state = hash_wait;
      else
        next_state = idle;
    hash_wait:
      if(hash_busy)
        next_state = hash_wait;
      else
        next_state = hash; 
    hash:
      if(multi_hash_en)
        next_state = lookup_wait;
      else
        next_state = hash;
    lookup_wait:
      if(read_now)
        next_state = lookup_wait;
      else
        next_state = renew;
    renew:
      if(renew_done)
        next_state = idle;
      else
        next_state = renew;
    ini_table:
        if(ini_table_done)
            next_state = idle;
        else
            next_state = ini_table;
    default:
        next_state = idle;
  endcase
always@(posedge clk or negedge rst_n)
begin
  if(~rst_n)
    begin                       
    multi_mac_cpu_reg    <=  0;
    multi_group_cpu_reg  <=  0;
    multi_member_cpu_reg <=  0;
    modify_reg           <=  0;
    wr_mac               <=  0;
    end
  else if(state==idle && wr_en_cpu)                          
    begin
      multi_mac_cpu_reg    <=  multi_group_mac_cpu[23:0];
      multi_group_cpu_reg  <=  multi_group_mac_cpu[31:24];
      multi_member_cpu_reg <=  multi_member_cpu;
      modify_reg           <=  multi_modify_cpu[2:1];
      wr_mac               <=  multi_group_mac_cpu[23:0];
    end
  else 
    begin                       
    multi_mac_cpu_reg    <=  multi_mac_cpu_reg   ;
    multi_group_cpu_reg  <=  multi_group_cpu_reg ;
    multi_member_cpu_reg <=  multi_member_cpu_reg;
    modify_reg           <=  modify_reg          ;
    wr_mac               <=  wr_mac              ;
    end
end
always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
      begin 
      multi_mac_hash_en <= 1'b0;
      multi_mac         <= 24'b0;
      end 
    else if(next_state==hash)
      begin 
      multi_mac_hash_en <= 1'b1;
      multi_mac         <= multi_mac_cpu_reg;
      end 
    else 
      begin 
      multi_mac_hash_en <= 1'b0;
      multi_mac         <= 24'h0;
      end 
end
always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
      multi_hash_mac_reg <= 0;
    else if(multi_hash_en)
      multi_hash_mac_reg <= multi_hash_mac;
    else 
      multi_hash_mac_reg <= multi_hash_mac_reg;
end
always@(posedge clk or negedge rst_n)
begin
  if(~rst_n)
    renew_busy <= 1'b0;
  else if(next_state == idle)
    renew_busy <= 1'b0;
  else 
    renew_busy <= 1'b1;
end

always@(posedge clk or negedge rst_n)
begin
  if(~rst_n)
    begin
      addr_a <=  10'd0;
      data_a <=  72'd0;
      wren_a <=  1'b0;
    end
  else if(next_state == ini_table)
    begin
      addr_a <=  ini_addr;
      data_a <=  72'd0;
      wren_a <=  1'b1;
    end
  else if(next_state == renew)
    begin
      if(step == 4'd0)
      begin 
        addr_a <= multi_hash_mac_reg;
        wren_a <= 1'b0;
        data_a <= 72'h0;
      end 
      else if(step == 4'd2 && modify_reg == 2'b11 && q_a[32]==1'b0)
      begin
        addr_a <= addr_a;
        wren_a <= 1'b1;
        data_a <= {7'd0,multi_mac_cpu_reg,multi_group_cpu_reg,1'b1,multi_member_cpu_reg};
      end
      else if(step == 4'd2 && modify_reg == 2'b10 && q_a[64:41]==multi_mac_cpu_reg)
      begin
        addr_a <= addr_a;
        wren_a <= 1'b1;
        data_a <= {7'd0,multi_mac_cpu_reg,multi_group_cpu_reg,1'b1,multi_member_cpu_reg};  
      end
      else if(step==4'd2 && modify_reg == 2'b01 && q_a[64:41]==multi_mac_cpu_reg)
      begin
        addr_a <= addr_a;
        wren_a <= 1'b1;
        data_a <= 72'h0; 
      end
      else 
      begin
        addr_a <=  addr_a;
        data_a <=  72'd0;
        wren_a <=  1'b0;   
      end
    end
  else 
    begin 
      addr_a <= 0;
      wren_a <= 0;
      data_a <= 0;
    end 
end
always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
      step <= 4'd0;
    else if(next_state == renew)
      step <= step +1;
    else 
      step <= 0;
end
always@(posedge clk or negedge rst_n)
begin
    if(~rst_n)
      renew_done <= 1'b0;
    else if(state == renew && step ==4'd3)
      renew_done <= 1'b1;
    else 
      renew_done <= 1'b0;
end
endmodule
